﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Repo7.BusinessLogic.Local;
using Repo7.BusinessLogic.Utils;
using Repo7.BusinessLogic.Network.Cluster;
using Repo7.BusinessLogic.Network.Commander;
using log4net;
using log4net.Config;
using Repo7.BusinessLogic.Network.FileTransfer;
using System.IO;

namespace Repo7.BusinessLogic
{
    /// <summary>
    /// Repository Manager
    /// </summary>
    public class RepoManager
    {
        #region Propreties

        /// <summary>
        /// Logger
        /// </summary>
        private static readonly ILog logger = LogManager.GetLogger(typeof(RepoCommander));

        /// <summary>
        /// Repository repo.info Manager
        /// </summary>
        public RepoInfoManager RepoInfoManager { get; private set;}

        /// <summary>
        /// Cluster Manager
        /// </summary>
        public RepoClusterManager ClusterManager { get; private set; }

        /// <summary>
        /// Commander Server
        /// </summary>
        public RepoCommander RepoCommander { get; private set; }

        /// <summary>
        /// File Transfer
        /// </summary>
        public RepoFileTransfer RepoFileTransfer {get; private set;}

        /// <summary>
        /// Repository Watcher
        /// </summary>
        public RepoWatcher RepoWatcher { get; private set; }

        #endregion

        #region Constructor

        public RepoManager()
        {
            //Init log4net
            XmlConfigurator.Configure();
        }

        #endregion

        #region Methods

        public void  InitRepoManager()
        {
            //Get cluster information
            ClusterManager = new RepoClusterManager();
            ClusterManager.InitPeerList();

            //Get local repository file info
            RepoInfoManager = new RepoInfoManager(ClusterManager.LocalInformation.RepoFolderPath);
            RepoInfoManager.InitRepositoryFilesInfo();

            //Init Commander Server
            RepoCommander = new RepoCommander(new Action<RepoCommand>(CommandInterpreter), null);
            RepoCommander.StartListening(ClusterManager.LocalInformation.CommandEndPont);

            //Init File Transfer Server
            RepoFileTransfer = new RepoFileTransfer(ClusterManager.LocalInformation.RepoFolderPath);
            RepoFileTransfer.StartListening(ClusterManager.LocalInformation.FileTransferEndPoint);

            //Init Repo Watcher
            RepoWatcher = new RepoWatcher(ClusterManager.LocalInformation.RepoFolderPath);
            RepoWatcher.SetupWatcherEventHandlers(OnCreated, null, null, null);
            RepoWatcher.StartObservingRepository();
        }

        #endregion

        #region Private Methods

        internal void CommandInterpreter(RepoCommand command)
        {
            logger.DebugFormat("Received command: {0} [{1}] : {2} -> {3} ",
                command.CommandType, command.FileName, command.ReceiveEndPoint, command.SendToEndPoint);
        }

        /// <summary>
        /// On Created Event Handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>
        private void OnCreated(object sender, FileSystemEventArgs eventArgs)
        {
            //Adding file to repository info
            FileInfo newFile = new FileInfo(eventArgs.FullPath);
            var repoFileInfo = FileUtils.CreateRepositoryFile(newFile);
            RepoInfoManager.AddFile(repoFileInfo);
            logger.Info(string.Format("Added file '{0}' to the repository.", eventArgs.Name));

            //Send the file to other peers if the current node is the master
            if (ClusterManager.LocalInformation.IsMaster)
            {
                foreach (var peer in ClusterManager.Peers)
                {
                    RepoFileTransfer.SendFile(newFile.FullName, peer.FileTransferEndPoint);
                }
            }
        }

        #endregion


    }
}
